<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>13-加载3D模型</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    html,
    body {
      width: 100%;
      height: 100%;
    }
    .tools {
      width: 100%;
      position: absolute;
      top: 0;
      left: 0;
      z-index: 2;
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 4px 10px;
      box-sizing: border-box;
    }
  </style>
</head>

<body>
  <div class="tools">
    <p class="process">90</p>
    <input type="color" id="color"/>
  </div>
  <script type="module">
    import * as THREE from "three";
    import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
    import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
    import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
    import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
    import { Timer } from "three/addons/misc/Timer";
    import * as CANNON from "cannon";
    // 创建场景
    const scene = new THREE.Scene();
    // 设置背景颜色
    scene.background = new THREE.Color(0xbfd1e5);
    // 创建相机
    const camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      1,
      1000
    );
    // camera.position.set(-0, 1, 3.5);
    camera.position.set(0, 1.5, -3.5);
    camera.lookAt(0, 0, 0);
    // 创建渲染器 
    const renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    // 设置渲染器大小
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    // 把渲染的canvas内容添加到body
    document.body.appendChild(renderer.domElement);

    
    //光照
    const light = new THREE.AmbientLight(0xffffff); // 柔和的白光
    scene.add(light);
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
    scene.add(directionalLight);


    // 创建轨道控制器
    const controls = new OrbitControls(camera, renderer.domElement);

    // 方便摆放模型位置
    // controls.addEventListener("change", () => {
    //   console.log(camera.position);
    // })

    // 开启物体的阻尼动画效果 
    controls.enableDamping = true;

    const oProcess = document.querySelector(".process");
    const oInput = document.querySelector("#color");
    let chair;
    oInput.addEventListener("change", (e) => {
      if(chair) {
        chair.material.color.set(e.target.value);
      }
    });
    const gltfLoader = new GLTFLoader();
    let mixer;
    let runAction;
    let walkAction;
    let IdleAction;
    let poseAction;
    let currentAction;
    gltfLoader.load(
      "../models/Soldier.glb",
      (gltf) => {
        const model = gltf.scene;
        chair = gltf.scene.children[0].children[0];
        const animations = gltf.animations;
        mixer = new THREE.AnimationMixer(model);
        scene.add(model);

        // 奔跑
        const runClip = animations.find((clip) => clip.name === "Run");
        // 步行
        const walkClip = animations.find((clip) => clip.name === "Walk");
        // 摆pose
        const poseClip = animations.find((clip) => clip.name === "TPose");
        // 站立
        const IdleClip = animations.find((clip) => clip.name === "Idle");

        if(runClip && IdleClip) {
          runAction = mixer.clipAction(runClip);
          IdleAction = mixer.clipAction(IdleClip);
          // 默认站立
          IdleAction.play();
          currentAction = IdleAction;
        }

        if(walkClip) {
          walkAction = mixer.clipAction(walkClip);
        }

        if(poseClip) {
          poseAction = mixer.clipAction(poseClip);
        }
        
        console.log(animations);
      },
      (xhr) => {
        const percent = (xhr.loaded / xhr.total) * 100;
        oProcess.textContent = `${Math.round(percent, 2)}%`;
      },
      (err) => {
        console.log(err.message);
      }
    );

    // 键盘监听
    document.addEventListener("keydown", (e) => {
      switch(e.code) {
        case "KeyW":
          if(currentAction !== walkAction && currentAction !== runAction) {
            // 步行
            currentAction.fadeOut(0.5);
            walkAction.reset().fadeIn(0.5).play();
            currentAction = walkAction;
          }
          if(e.shiftKey && currentAction !== runAction) {
            // 奔跑
            currentAction.fadeOut(0.5);
            runAction.reset().fadeIn(0.5).play();
            currentAction = runAction;
          } 
          break;
        case "KeyH":
          if(poseAction && currentAction !== poseAction) {
            // 摆pose
            currentAction.fadeOut(0.5);
            poseAction.reset().fadeIn(0.5).play();
            currentAction = poseAction;
          }
          break;
      }
    });

    document.addEventListener("keyup", (e) => {
      switch (e.code) {
        case "KeyW":
          if(currentAction !== IdleAction) {
            currentAction.fadeOut(0.5);
            IdleAction.reset().fadeIn(0.5).play();
            currentAction = IdleAction;
          }
          break;
        case "KeyH":
          if(currentAction !== IdleAction) {
            currentAction.fadeOut(0.5);
            IdleAction.reset().fadeIn(0.5).play();
            currentAction = IdleAction;
          }
          break;
        case "ShiftLeft":
          if(currentAction !== IdleAction) {
            currentAction.fadeOut(0.5);
            walkAction.reset().fadeIn(0.5).play();
            currentAction = walkAction;
          }
          break;
      }
    });

    // 监听controls的change事件
    controls.addEventListener("change", () => {
      // 交互的鼠标每次发生变化，都需要渲染一次(如果用了animate函数就不需要).
      renderer.render(scene, camera);
    });
    renderer.render(scene, camera);

    // 此类是 Clock 的替代品，具有不同的 API 设计和行为。目标是避免随着时间的推移 Clock 中变得明显的概念缺陷。
    const timer = new Timer();
    function animate(timestamp) {
      requestAnimationFrame(animate);
      timer.update(timestamp);
      const delta = timer.getDelta();
      if(mixer) mixer.update(delta);
      controls.update();
      renderer.render(scene, camera);
    } 
    
    // 添加动画并渲染
    animate();
  </script>
</body>

</html>